home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Experimental BBS Explossion 3
/
Experimental BBS Explossion III.iso
/
c
/
kafsort.zip
/
KAFS.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-05-28
|
17KB
|
554 lines
/****************************************************************
* KAFS.C
*
* Keyed Access File Definitions
*
* Keyed Access File System Version 2.0
*
* 2.0 Revised to contain keys and data in a single file.
* Key Access Files (KAF) are self contained.
* 9/23/92 - Added 'filecommit' function in KAFS.
* 2.1 11/11/92 - Qualified rec value for delete, read_rec, write_rec
*
****************************************************************/
#include <dos.h>
#include <fcntl.h>
#include <stdio.h>
#include <math.h>
#include <sys\stat.h>
/**********************************************************
* Key Access files definitions
**********************************************************/
#define TRUE 1
#define FALSE 0
#define OK 0
#define SOF -1 /* Start of File */
#define FCLOSED -1
#define ERR -1
#define NOTFOUND -2
#define FILEFULL -3
#define KAEOF -4 /* Reached End Of File on Sequential Read */
/**
** KEY ACCESS ERROR CODES - Value held in kaerror global Variable
**
1 - File Already Open
2 - Not a valid KAFSII file
3 - Error Attempting to Open Data File
4 - File Not Open
5 - Seek Error on Data File
6 - Read Error on Data File
7 - Write Error on Data File
8 - Error Reading Hash Index Block
9 - Error Writing Hash Index Block
10 - Invalid Channel Number
11 - Passed Key Argument exceeds keysize
12 - File Name too Long or Invalid
13 - Rec exceeds file's extent
**
**/
#define HBLOCKSIZE 1024
#define KEYSTART 128 /* Start of File's Key Blocks */
#define KEYFILES 16 /* Number of key files allowed */
#define MAXRECSIZE 512 /* Maximum Record Size allowed */
#define MAXKEYSIZE 40 /* Maximum Key Size allowed */
/* ------------- File Definition Structure (Allow 256 Bytes) --------- */
struct fildef {
char signature[7]; /* KAFSII */
char filename[16]; /* User's File Name */
int keysize; /* Size of Key Field */
int recsize; /* Size of a Record */
long records; /* Number of Records */
int kpb; /* Keys per Block */
long hblocks; /* Hash blocks (calculated) */
long dbeg; /* File Position for Data Beginning */
};
/* ------------- File Table Definition ---------------- */
struct ft {
int handle; /* Data File's handle */
int keysize; /* Size of the key field */
int recsize; /* Size of record */
char fname[16];/* Filename (User's) */
long records; /* File defined max records */
long hblocks; /* Hash blocks (calculated) */
int kpb; /* Keys per block (calculated) */
long dbeg; /* File position for beginning of Data */
};
/*********************************************************************
* Function Prototypes
*********************************************************************/
int ka_open(int, char *);
void ka_close_all(void);
void ka_close(int);
int read_key(int, char *, void *);
int read_rec(int, void *);
int read_xrec(int, void *);
int write_key(int, char *, void *);
int write_rec(int, void *);
int write_upd(int, void *);
int rdelete(int, long);
int read_seq(int, void *);
int read_hblk(int, long);
int write_hblk(int, long);
long khash(char *, long);
void filecommit(int);
char hbuf[HBLOCKSIZE]; /* Define the Hash Buffer */
long rec; /* Global Record Number */
int kaerror = 0; /* Global Error Code */
char *kaversion = "V2.01 - 11/11/92"; /* Version 2.0 */
char key[MAXKEYSIZE+1]; /* Global Key 40 chars max */
/* Define the file table structure */
struct ft ftbl[KEYFILES+1]=
{-1,0,0,"",0,0,0,0,
-1,0,0,"",0,0,0,0,
-1,0,0,"",0,0,0,0,
-1,0,0,"",0,0,0,0,
-1,0,0,"",0,0,0,0,
-1,0,0,"",0,0,0,0,
-1,0,0,"",0,0,0,0,
-1,0,0,"",0,0,0,0,
-1,0,0,"",0,0,0,0,
-1,0,0,"",0,0,0,0,
-1,0,0,"",0,0,0,0,
-1,0,0,"",0,0,0,0,
-1,0,0,"",0,0,0,0,
-1,0,0,"",0,0,0,0,
-1,0,0,"",0,0,0,0,
-1,0,0,"",0,0,0,0};
struct fildef fdef; /* File Definition structure */
/********************************************************************
* KA_OPEN - Open a keyed access file.
*
* All Keyed Access files have the extension 'KAF'.
*
********************************************************************/
ka_open(int fn, char * fname)
{
unsigned mode;
char buffer[256]; /* Used to build filename & read in file defs */
if(strlen(fname)>76) /* Validate filename parameter */
{
kaerror = 12; /* Filename too Long */
return(ERR);
}
if(fn <0 || fn >= KEYFILES) /* Validate filenumber */
{
kaerror = 10; /* Invalid Channel Number */
return(ERR);
}
if(ftbl[fn].handle != -1)
{
kaerror = 1;
return(ERR); /* File already Open */
}
strcpy(buffer, fname); /* Build the KAF filename */
strcat(buffer, ".KAF");
/*
* Set the mode for opening or for Creating a new file
*/
mode = O_RDWR | O_BINARY | O_DENYNONE;
ftbl[fn].handle = open(buffer, mode ,S_IREAD | S_IWRITE);
if(ftbl[fn].handle==ERR)
{
kaerror = 3; /* Unable to Open File */
return(ERR);
}
/*
* Read the File's Definition and set the file table values
*/
if(read(ftbl[fn].handle, &fdef, sizeof(fdef))==ERR ||
strcmp(fdef.signature, "KAFSII"))
{
kaerror = 2; /* Not a KAFSII file */
return(ERR);
}
ftbl[fn].keysize = fdef.keysize; /* size of key */
ftbl[fn].recsize = fdef.recsize; /* Record size */
ftbl[fn].records = fdef.records;
ftbl[fn].kpb = fdef.kpb; /* Keys per Block */
ftbl[fn].hblocks =fdef.hblocks; /* Number of hash Blocks */
ftbl[fn].dbeg = fdef.dbeg; /* Start of Data Pointer */
strcpy(ftbl[fn].fname, fdef.filename);
return(OK);
}
/** -------- Close Files -------- */
void ka_close_all(void)
{
int i;
for(i=0;i<KEYFILES;i++) ka_close(i);
}
void ka_close(int fn)
{
if(ftbl[fn].handle > -1) close(ftbl[fn].handle);
ftbl[fn].handle = -1;
}
/** -----------------------------------------------------------------
** READ_KEY - Read a key access file by key.
** This function hashes the key to find the record if Rec = SOF
** If Rec != SOF reads for key at rec + 1
** ----------------------------------------------------------------- */
read_key(int fn, char *keyarg, void *buffer)
{
long hblk;
long startblock; /* Starting point for search */
int brec; /* Record number in Block */
char *hp;
key[0]=0; /* Blank Key for Return */
if(ftbl[fn].handle == FCLOSED || fn < 0 || fn >= KEYFILES)
{
kaerror = 4; /* File not open */
return(ERR);
}
if(rec==SOF)
{
hblk = khash(keyarg, ftbl[fn].hblocks); /* Get the Hashed Block */
rec = hblk * ftbl[fn].kpb; /* Calculate record number at beginning */
}
else
{
rec++;
if(rec > ftbl[fn].records) rec = 0; /* Wrap At EOF */
hblk = (long)rec/ftbl[fn].kpb; /* Or block based on rec */
}
if(read_hblk(ftbl[fn].handle, hblk)==ERR) return(ERR);
startblock = hblk; /* Save for wrap-arounds */
brec = rec - (hblk * ftbl[fn].kpb);
hp = hbuf + (brec * ftbl[fn].keysize); /* point to Record in Buffer */
while(TRUE)
{
if(*hp == 0) return(NOTFOUND);
if(!strcmp(hp,keyarg))
{
strcpy(key,hp); /* copy the key */
return(read_xrec(fn, buffer)); /* FOUND */
}
rec++; /* Bump the record number */
brec++; /* Bump the block record number */
hp += ftbl[fn].keysize; /* Move the Pointer to the next key */
if(brec>=ftbl[fn].kpb)
{
hblk++;
if(hblk >= ftbl[fn].hblocks) hblk=0; /* Wrap around at EOF */
if(hblk == startblock) return(NOTFOUND); /* Oops We wrapped around */
if(read_hblk(ftbl[fn].handle, hblk)==ERR) return(ERR); /* Read Nxt Blk */
hp = hbuf; /* Point to beginning of block */
brec = 0;
rec = hblk * ftbl[fn].kpb; /* Calculate Record # */
}
}
}
/** -----------------------------------------------------------------
** READ_REC - External Access to Read a key access file by Record Number.
** This function reads only the Data portion of a record.
** Returns the key for the record in global key.
**
** 2.0 Modified to Add Data Offset
** ----------------------------------------------------------------- */
read_rec(int fn, void *buffer)
{
long hblk; /* Hash Block number */
int brec;
char *kp;
if(read_xrec(fn, buffer)==ERR) return(ERR); /* Get Data First */
hblk = (long)rec / ftbl[fn].kpb; /* get the hash index block no. */
if(read_hblk(ftbl[fn].handle, hblk)==ERR) return(ERR);
brec = rec-(hblk * ftbl[fn].kpb); /* Rec # offset into this block */
kp = hbuf + (brec * ftbl[fn].keysize); /* point to the record */
strcpy(key,kp); /* Copy in the Key */
return(OK);
}
/** -----------------------------------------------------------------
** READ_XREC - Internal Access to Read a key access file by Record Number.
** This function reads only the Data portion of a record.
** ----------------------------------------------------------------- */
read_xrec(int fn, void *buffer)
{
long fpos;
if(ftbl[fn].handle == FCLOSED || fn < 0 || fn >= KEYFILES)
{
kaerror = 4; /* File not open */
return(ERR);
}
if(rec > ftbl[fn].records || rec < 0)
{
kaerror = 13; /* Beyond File Limit */
return(ERR);
}
fpos = ((long)rec * ftbl[fn].recsize) + ftbl[fn].dbeg;
if(lseek(ftbl[fn].handle,fpos,0)==ERR)
{
kaerror = 5; /* Seek Error on Data File */
return(ERR);
}
if(read(ftbl[fn].handle, buffer,(unsigned)ftbl[fn].recsize)==ERR)
{
kaerror = 6; /* Read Error on Data File */
return(ERR);
}
return(OK);
}
/** -----------------------------------------------------------------
** WRITE_KEY - Write a new record to a key access file by key.
** This function hashes the key to find the record.
** ----------------------------------------------------------------- */
write_key(int fn, char *keyarg, void *buffer)
{
long hblk;
long startblock; /* Starting point for search */
int brec; /* Record number in Block */
char *hp;
if(ftbl[fn].handle == FCLOSED || fn < 0 || fn >= KEYFILES)
{
kaerror = 4; /* File not open */
return(ERR);
}
if(strlen(keyarg)>ftbl[fn].keysize-1)
{
kaerror = 11; /* key too big */
return(ERR);
}
hblk = khash(keyarg, ftbl[fn].hblocks); /* Get the Hashed Block */
if(read_hblk(ftbl[fn].handle, hblk)==ERR) return(ERR);
hp = hbuf; /* Point to beginning of Buffer */
rec = hblk * ftbl[fn].kpb; /* Calculate record number */
startblock = hblk; /* Save for wrap-arounds */
brec = 0;
while(1)
{
if(*hp < 02) /* Found an Empty Slot, empty (00) or deleted (01) */
{
if(write_rec(fn, buffer)==ERR) return(ERR); /* Write the Data */
strcpy(hp,keyarg); /* Copy in the Key */
if(write_hblk(ftbl[fn].handle, hblk)==ERR) return(ERR);
else return(OK);
}
rec++; /* Bump the record number */
brec++; /* Bump the block record number */
hp += ftbl[fn].keysize; /* Move the Pointer to the next key */
if(brec>=ftbl[fn].kpb)
{
hblk++;
if(hblk >= ftbl[fn].hblocks) hblk=0; /* Wrap around at EOF */
if(hblk == startblock) return(FILEFULL); /* Oops We wrapped around */
if(read_hblk(ftbl[fn].handle, hblk)==ERR) return(ERR); /* Read Nxt Blk */
hp = hbuf; /* Point to beginning of block */
brec = 0;
rec = hblk * ftbl[fn].kpb; /* Calculate Record # */
}
}
}
/** -----------------------------------------------------------------
** WRITE_REC - Write a record to a key access file by Record #.
** This function only writes the Data Portion of a record
**
** 2.0 Modified to add data beginning offset
**
** ----------------------------------------------------------------- */
write_rec(int fn, void *buffer)
{
int fh;
long fpos;
if(ftbl[fn].handle == FCLOSED || fn < 0 || fn >= KEYFILES)
{
kaerror = 4; /* File not open */
return(ERR);
}
if(rec > ftbl[fn].records || rec < 0)
{
kaerror = 13; /* Beyond File Limit */
return(ERR);
}
fh = ftbl[fn].handle; /* Set file handle */
fpos = ((long)rec * ftbl[fn].recsize) + ftbl[fn].dbeg;
if(lseek(fh,fpos,0)==ERR)
{
kaerror = 5; /* Seek Error */
return(ERR);
}
if(write(fh, buffer,(unsigned)ftbl[fn].recsize)==ERR)
{
kaerror = 7; /* Write Error */
return(ERR);
}
return(OK);
}
write_upd(int fn, void *buffer)
{
return(write_rec(fn, buffer));
}
/** -----------------------------------------------------------------
** RDELETE - Delete a record in a key access file by record number.
** The record must have previously been read and rec # obtained
** ----------------------------------------------------------------- */
rdelete(int fn, long delrec)
{
long hblk;
int brec;
char * hp;
if(ftbl[fn].handle == FCLOSED || fn < 0 || fn >= KEYFILES)
{
kaerror = 4; /* File not open */
return(ERR);
}
if(rec > ftbl[fn].records || rec < 0)
{
kaerror = 13; /* Beyond File Limit */
return(ERR);
}
rec = delrec;
hblk = (long)delrec / ftbl[fn].kpb; /* get the hash index block no. */
if(read_hblk(ftbl[fn].handle, hblk)==ERR) return(ERR); /* read it */
brec = rec-(hblk * ftbl[fn].kpb); /* Rec # offset into this block */
hp = hbuf + (brec * ftbl[fn].keysize); /* point to the record */
*hp = 01; /* Delete the Record */
if(write_hblk(ftbl[fn].handle, hblk)==ERR) return(ERR); /* Write it */
return(OK);
}
/** -----------------------------------------------------------------
** READ_SEQ - Read sequential. Reads next record based on rec.
** Esentially reads rec+1 for next available record.
** ----------------------------------------------------------------- */
read_seq(int fn, void *buffer)
{
long hblk;
int brec;
char *hp;
if(ftbl[fn].handle == FCLOSED || fn < 0 || fn >= KEYFILES)
{
kaerror = 4; /* File not open */
return(ERR);
}
key[0]=0; /* Null the key */
while(TRUE)
{
if(rec+1 > ftbl[fn].records) return(KAEOF); /* End of file */
rec++; /* increment record */
hblk = rec / ftbl[fn].kpb; /* get the hash index block no. */
if(read_hblk(ftbl[fn].handle, hblk)==ERR) return(ERR);
brec = rec-(hblk * ftbl[fn].kpb); /* Rec # offset into this block */
hp = hbuf + (brec * ftbl[fn].keysize); /* point to the record */
if(*hp > 2)
{
strcpy(key, hp); /* Copy the key into the key storage */
return(read_xrec(fn, buffer)); /* Read the record & return */
}
if(*hp == 0) /* NO more recs this block */
{
hblk++;
if(hblk >= ftbl[fn].hblocks) return(KAEOF); /* At EOF */
rec = (hblk * ftbl[fn].kpb)-1; /* Get beginning rec number -1 */
}
}
}
/** -----------------------------------------------------------------
** READ_HBLK - Read Hash Block to Hash Block Buffer
**
** 2.0 Modified to add key offset
** ----------------------------------------------------------------- */
read_hblk(int fh, long blkno)
{
kaerror = 8;
if(lseek(fh, ((long)blkno * HBLOCKSIZE)+KEYSTART, 0)==ERR) return(ERR);
return(read(fh, hbuf, (unsigned)HBLOCKSIZE));
}
/** -----------------------------------------------------------------
** WRITE_HBLK - Write Hash Block from Hash Block Buffer
**
** 2.0 Modified to add key offset
** ----------------------------------------------------------------- */
write_hblk(int fh, long blkno)
{
kaerror = 9;
if(lseek(fh, ((long)blkno * HBLOCKSIZE)+KEYSTART, 0)==ERR) return(ERR);
return(write(fh, hbuf, (unsigned)HBLOCKSIZE));
}
/** ------------------------------------------------------------------
** KHASH - Hash a key and return the hash block number
** ------------------------------------------------------------------ */
long khash(char *hkey, long blocks)
{
char *hp;
double hc;
long val;
hc = (double)blocks-1;
hp = hkey; /* Point to key for Hashing */
while (*hp) hc += *hp++ - 32;
val = (long)fmod(hc, (double)blocks);
return(val);
}
/**************************************************************************
* FILECOMMIT - Commit a file's changes etc to disk. Flush.
*************************************************************************/
void filecommit(int fnum)
{
union REGS regs;
int rc, ec;
regs.h.ah = 0x68; /* Call to Flush */
regs.x.bx = ftbl[fnum].handle; /* Give the file's handle */
intdos(®s, ®s);
rc = regs.x.cflag;
if(rc != 0) ec = _doserrno;
}